package it.prova;

import it.prova.transform.MultiDataUnitTransformOperation;
import it.prova.xml.MyOutputSerializer;
import it.prova.xml.MySerializer;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import nu.xom.Attribute;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Elements;
import nu.xom.Node;
import nu.xom.Nodes;
import nu.xom.Text;

import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.IFileSystem;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jst.jsf.metadataprocessors.features.PossibleValue;
import org.eclipse.jst.pagedesigner.dtmanager.converter.ITagConverterContext;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.w3c.dom.NodeList;

public class Utility
{
	private static IFile getCurrentOpenFile()
	{
//		PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable()
//		{
//			public void run()
//			{
				IWorkbench wb = PlatformUI.getWorkbench();
				IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
				if(win != null)
				{
					IWorkbenchPage page = win.getActivePage();
					if(page != null)
					{
						IEditorPart part = page.getActiveEditor();
						if(part != null)
						{
							IEditorInput editor = part.getEditorInput();
							IFileEditorInput fileEditor = (IFileEditorInput) editor;
							return fileEditor.getFile();
						}
					}
				}
				return null;
//			}
//		});
	}
	
	public static IPath getCurrentOpenFilePath()
	{
		IFile currentOpenFile = getCurrentOpenFile();
		
		IPath fullPath = null;
		if(currentOpenFile != null)
		{
			fullPath = currentOpenFile.getLocation();
		}
		return fullPath;
	}
	
	private static IFileStore getCurrentOpenModelFileStore()
	{
//		if(currentOpenFile == null)
//		{
//			getCurrentOpenFile();
//		}
		IFile currentOpenFile = getCurrentOpenFile();
		
		IFileStore newFileStore = null; 
		if(currentOpenFile != null)
		{
			IPath fullPath = currentOpenFile.getLocation();
			String newFilePath = fullPath.toString().substring(0, fullPath.toString().lastIndexOf(".")+1);
			String newFileFullPath = newFilePath + Consts.MODEL_FILE_EXTENSION;
			
			IFileSystem fileSystem = EFS.getLocalFileSystem();
			
			newFileStore = fileSystem.getStore(URI.create(newFileFullPath));
		}
		return newFileStore;
	}
	
	public static IFile getCurrentOpenModelFile()
	{
		IFileStore currentOpenModelFileStore = getCurrentOpenModelFileStore();
		
		IFile newFile = null; 
		if(currentOpenModelFileStore != null)
		{
			IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(currentOpenModelFileStore.toURI());
			newFile = files[0];
		}
		return newFile;
	}
	
	public static IPath getCurrentOpenModelPath()
	{
		IFile currentOpenModelFile = getCurrentOpenModelFile();
		
		IPath currentOpenModelPath = null;
		if(currentOpenModelFile != null)
		{
			currentOpenModelPath = currentOpenModelFile.getFullPath();
		}
		return currentOpenModelPath;
	}
	
	public static Document getCurrentModel(int unitType)
	{
		IFile currentOpenFile = getCurrentOpenFile();
		IFileStore currentOpenModelFileStore = getCurrentOpenModelFileStore();
		
		Document document = null;
		if((currentOpenFile != null) && (currentOpenModelFileStore != null))
		{
			IPath fullPath = currentOpenFile.getLocation();
			String newFilePath = fullPath.toString().substring(0, fullPath.toString().lastIndexOf(".")+1);
			String newFileFullPath = newFilePath + Consts.MODEL_FILE_EXTENSION;
			
			IFileSystem fileSystem = EFS.getLocalFileSystem();
			
			IFileStore newFileStore = fileSystem.getStore(URI.create(newFileFullPath));
			IFileInfo newFileInfo = newFileStore.fetchInfo();
			
			try
			{
				if(!newFileInfo.exists())
				{
					IFileStore defaultTemplateFileStore = null;
					switch(unitType)
					{
						case Consts.DATA_UNIT:
							defaultTemplateFileStore = fileSystem.getStore(URI.create(Consts.DATA_UNIT_MODEL_FILE_PATH));
							break;
						case Consts.MULTI_DATA_UNIT:
							defaultTemplateFileStore = fileSystem.getStore(URI.create(Consts.MULTI_DATA_UNIT_MODEL_FILE_PATH));
							break;
						case Consts.ENTRY_UNIT:
							defaultTemplateFileStore = fileSystem.getStore(URI.create(Consts.ENTRY_UNIT_MODEL_FILE_PATH));
							break;
					}
					defaultTemplateFileStore.copy(newFileStore, EFS.NONE, null);
				}
				
				Builder parser = new Builder();
				document = parser.build(newFileStore.openInputStream(EFS.NONE, null));
				
				Nodes units = null;
				
				switch(unitType)
				{
					case Consts.DATA_UNIT:
						IFileStore dataUnitPageFileStore = fileSystem.getStore(URI.create(Consts.DATA_UNIT_PAGE_FILE_PATH));
						Document dataUnitPage = parser.build(dataUnitPageFileStore.openInputStream(EFS.NONE, null));
						
						units = dataUnitPage.query
						(
							Consts.DATA_UNIT_PAGE_ATTRIBUTES_QUERY + "[@" + Consts.PAGE_DISPLAY_ATTRIBUTES_NAME + 
							" and @" + Consts.PAGE_ENTITY_NAME + " and @" + Consts.PAGE_ID + "]"
						);
						break;
					case Consts.MULTI_DATA_UNIT:
						IFileStore multiDataUnitPageFileStore = fileSystem.getStore(URI.create(Consts.MULTI_DATA_UNIT_PAGE_FILE_PATH));
						Document multiDataUnitPage = parser.build(multiDataUnitPageFileStore.openInputStream(EFS.NONE, null));
						
						units = multiDataUnitPage.query
						(
							Consts.MULTI_DATA_UNIT_PAGE_ATTRIBUTES_QUERY + "[@" + Consts.PAGE_DISPLAY_ATTRIBUTES_NAME + 
							" and @" + Consts.PAGE_ENTITY_NAME + " and @" + Consts.PAGE_ID + "]"
						);
						break;
					case Consts.ENTRY_UNIT:
						IFileStore entryUnitPageFileStore = fileSystem.getStore(URI.create(Consts.ENTRY_UNIT_PAGE_FILE_PATH));
						Document entryUnitPage = parser.build(entryUnitPageFileStore.openInputStream(EFS.NONE, null));
						
						units = entryUnitPage.query
						(
							Consts.ENTRY_UNIT_PAGE_ATTRIBUTES_QUERY + "[@" + Consts.PAGE_ID + "]"
						);
						break;
				}
				
				if
				(
					unitType == Consts.DATA_UNIT || 
					unitType == Consts.MULTI_DATA_UNIT
				)
				{
					if(units.size() > 1)
					{
						System.out.println
						(
							"More than one tag with '" + Consts.PAGE_DISPLAY_ATTRIBUTES_NAME + 
							"', '" + Consts.PAGE_ENTITY_NAME + "' and '" + Consts.PAGE_ID + "' attributes in default page"
						);
					}
					else if(units.size() < 1)
					{
						System.out.println
						(
							"No tags with '" + Consts.PAGE_DISPLAY_ATTRIBUTES_NAME + 
							"', '" + Consts.PAGE_ENTITY_NAME + "' and '" + Consts.PAGE_ID + "' attributes in default page"
						);
					}
					else
					{
						Element unitElement = (Element) units.get(0);
						
						Attribute displayAttribute = new Attribute(unitElement.getAttribute(Consts.PAGE_DISPLAY_ATTRIBUTES_NAME));
						Attribute entity = new Attribute(unitElement.getAttribute(Consts.PAGE_ENTITY_NAME));
						
						Attribute idAttribute = unitElement.getAttribute(Consts.PAGE_ID);
						String idValue = unitElement.getAttributeValue(Consts.PAGE_ID);
						String[] idValueSplitted = idValue.split("#");
						idValue = idValueSplitted[idValueSplitted.length-1];
						idAttribute.setValue(idValue);
						
						Attribute id = new Attribute(idAttribute);
						
						Attribute unitTypeAttribute = new Attribute(Consts.PAGE_UNIT_TYPE_NAME, String.valueOf(unitType));
						
						document.getRootElement().addAttribute(displayAttribute);
						document.getRootElement().addAttribute(entity);
						document.getRootElement().addAttribute(id);
						document.getRootElement().addAttribute(unitTypeAttribute);
						
						setCurrentModel(document);
					}
				}
				else if(unitType == Consts.ENTRY_UNIT)
				{
					if(units.size() > 1)
					{
						System.out.println
						(
							"More than one tag with '" + Consts.PAGE_ID + "' attributes in default page"
						);
					}
					else if(units.size() < 1)
					{
						System.out.println
						(
							"No tags with '" + Consts.PAGE_ID + "' attributes in default page"
						);
					}
					else
					{
						Element unitElement = (Element) units.get(0);
						
						String displayAttributeValue = "";
						for(int i=0; i<unitElement.getChildCount(); i++)
						{
							Node child = unitElement.getChild(i);
							
							if(child instanceof Element)
							{
								Element childElement = (Element) child;
								if(Consts.ENTRY_UNIT_PAGE_CHILD_FIELD_NAME.equals(childElement.getLocalName()))
								{
									displayAttributeValue += childElement.getAttributeValue(Consts.PAGE_ID) + " ";
								}
							}
						}
						// removing last white space
						displayAttributeValue.trim();
						
						Attribute displayAttribute = new Attribute(Consts.PAGE_DISPLAY_ATTRIBUTES_NAME, displayAttributeValue);
						
//						Attribute entity = new Attribute(createUnitElement.getAttribute(Consts.PAGE_ENTITY_NAME));
						
						Attribute idAttribute = unitElement.getAttribute(Consts.PAGE_ID);
						String idValue = unitElement.getAttributeValue(Consts.PAGE_ID);
						String[] idValueSplitted = idValue.split("#");
						idValue = idValueSplitted[idValueSplitted.length-1];
						idAttribute.setValue(idValue);
						
						Attribute id = new Attribute(idAttribute);
						
						Attribute unitTypeAttribute = new Attribute(Consts.PAGE_UNIT_TYPE_NAME, String.valueOf(unitType));
						
						document.getRootElement().addAttribute(displayAttribute);
//						document.getRootElement().addAttribute(entity);
						document.getRootElement().addAttribute(id);
						document.getRootElement().addAttribute(unitTypeAttribute);
						
						setCurrentModel(document);
						
//						Element unitElement = (Element) units.get(0);
//						String toValue = unitElement.getAttributeValue(Consts.MODEL_ATTRIBUTE_TO);
//						
//						IFileStore propertiesPageFileStore = fileSystem.getStore(URI.create(Consts.DEFAULT_PROPERTIES_PAGE_FILE_PATH));
//						
//						Document propertiesPage = parser.build(propertiesPageFileStore.openInputStream(EFS.NONE, null));
//						
//						Nodes entities = propertiesPage.query
//						(
//							Consts.PROPERTIES_PAGE_ATTRIBUTES_QUERY + "[@" + Consts.PAGE_ID + "=\"" + toValue + "\" and @" + 
//							Consts.PAGE_ENTITY_NAME + "]"
//						);
//						
//						if(entities.size() > 1)
//						{
//							System.out.println
//							(
//								"More than one tag with '" + Consts.PAGE_ENTITY_NAME + "' attribute and " + Consts.PAGE_ID + 
//								" attribute equals to '" + toValue + "' in default properties  page"
//							);
//						}
//						else if(entities.size() < 1)
//						{
//							System.out.println
//							(
//								"No tags with '" + Consts.PAGE_ENTITY_NAME + "' attribute and " + Consts.PAGE_ID + 
//								" attribute equals to '" + toValue + "' in default properties  page"
//							);
//						}
//						else
//						{
//							Element createUnitElement = (Element) entities.get(0);
//							
//							//Attribute displayAttribute = new Attribute(unitElement.getAttribute(Consts.PAGE_DISPLAY_ATTRIBUTES_NAME));
//							String displayAttributeValue = "";
//							for(int i=0; i<unitElement.getChildCount(); i++)
//							{
//								Node child = unitElement.getChild(i);
//								
//								if(child instanceof Element)
//								{
//									Element linkParameter = (Element) child;
//									String target = linkParameter.getAttributeValue(Consts.PAGE_TARGET_NAME);
//									if(target.lastIndexOf(".") > -1)
//									{
//										target = target.substring(target.lastIndexOf(".")+1);
//										displayAttributeValue += target + " ";
//									}
//								}
//							}
//							// removing last white space
//							displayAttributeValue.trim();
//							
//							Attribute displayAttribute = new Attribute(Consts.PAGE_DISPLAY_ATTRIBUTES_NAME, displayAttributeValue);
//							
//							Attribute entity = new Attribute(createUnitElement.getAttribute(Consts.PAGE_ENTITY_NAME));
//							
//							Attribute idAttribute = unitElement.getAttribute(Consts.PAGE_ID);
//							String idValue = unitElement.getAttributeValue(Consts.PAGE_ID);
//							String[] idValueSplitted = idValue.split("#");
//							idValue = idValueSplitted[idValueSplitted.length-1];
//							idAttribute.setValue(idValue);
//							
//							Attribute id = new Attribute(idAttribute);
//							
//							Attribute unitTypeAttribute = new Attribute(Consts.PAGE_UNIT_TYPE_NAME, String.valueOf(unitType));
//							
//							document.getRootElement().addAttribute(displayAttribute);
//							document.getRootElement().addAttribute(entity);
//							document.getRootElement().addAttribute(id);
//							document.getRootElement().addAttribute(unitTypeAttribute);
//							
//							setCurrentModel(document);
//						}
					}
				}
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
		return document;
	}
	
	public static void setCurrentModel(Document currentModel)
	{
		IFile currentOpenFile = getCurrentOpenModelFile();
		
		ByteArrayInputStream bIn = null;
		ByteArrayOutputStream bOut = null;
		if(currentOpenFile != null)
		{
			try
			{
				currentOpenFile.refreshLocal(IResource.DEPTH_INFINITE, null);
				
				bOut = new ByteArrayOutputStream();
				MySerializer s = new MySerializer(bOut);
				s.write(currentModel);
				
				byte[] currentModelBytes = bOut.toByteArray();
				
				bIn = new ByteArrayInputStream(currentModelBytes);
				currentOpenFile.setContents(bIn, IResource.FORCE, null);
			}
			catch(CoreException ce)
			{
				ce.printStackTrace();
			}
			catch(IOException ioe)
			{
				ioe.printStackTrace();
			}
			finally
			{
				if(bOut != null)
				{
					try
					{
						bOut.close();
					}
					catch(Exception e)
					{
						
					}
				}
				if(bIn != null)
				{
					try
					{
						bIn.close();
					}
					catch(Exception e)
					{
						
					}
				}
			}
		}
	}
	
	public static List<PossibleValue> getPossibleValues(Document currentModel)
	{
		List<PossibleValue> values = new ArrayList<PossibleValue>();
		
		if(currentModel != null)
		{
//			Elements attributes = currentModel.getRootElement().getChildElements("attribute");
			
//			for(int i=0; i<attributes.size(); i++)
//			{
//				values.add(new PossibleValue(attributes.get(i).getAttribute("name").getValue()));
//			}
			Attribute displayAttributes = currentModel.getRootElement().getAttribute(Consts.PAGE_DISPLAY_ATTRIBUTES_NAME);
			
			String[] tokens = displayAttributes.getValue().split("\\s");
			
			List<String> displayAttributesList = new ArrayList<String>();
			for(int i=0; i<tokens.length; i++)
			{
				displayAttributesList.add(tokens[i]);
			}
			
			Nodes attributeNodes = currentModel.query
			(
				Consts.MODEL_ATTRIBUTE_QUERY + "[@" + Consts.MODEL_ENTITY_ATTRIBUTE_NAME + "=\"" + Utility.getEntityName(currentModel) + 
				"\"]/" + Consts.MODEL_ATTRIBUTE_TAG
			);
			
			for(int i=0; i<attributeNodes.size(); i++)
			{
				Attribute attribute = ((Element)attributeNodes.get(i)).getAttribute(Consts.MODEL_ATTRIBUTE_NAME);
				
				if(displayAttributesList.contains(attribute.getValue()))
				{
					values.add(new PossibleValue(attribute.getValue()));
				}
			}
		}
		return values;
	}
	
	public static String getPageId(int unitType)
	{
		String pageId = null;
		
		IFileSystem fileSystem = EFS.getLocalFileSystem();
		IFileStore pageFileStore = null;
		switch(unitType)
		{
			case Consts.DATA_UNIT:
				pageFileStore = fileSystem.getStore(URI.create(Consts.DATA_UNIT_PAGE_FILE_PATH));
				break;
			case Consts.MULTI_DATA_UNIT:
				pageFileStore = fileSystem.getStore(URI.create(Consts.MULTI_DATA_UNIT_PAGE_FILE_PATH));
				break;
			case Consts.ENTRY_UNIT:
				pageFileStore = fileSystem.getStore(URI.create(Consts.ENTRY_UNIT_PAGE_FILE_PATH));
				break;
		}
		
		Builder parser = new Builder();
		try
		{
			Document pageDocument = parser.build(pageFileStore.openInputStream(EFS.NONE, null));
			
			Nodes pages = pageDocument.query
			(
				Consts.PAGE_QUERY + "[@" + Consts.PAGE_ID + "]"
			);
			
			if(pages.size() > 1)
			{
				System.out.println
				(
					"More than one tag with '" + Consts.PAGE_ID + "' attribute in page"
				);
			}
			else if(pages.size() < 1)
			{
				System.out.println
				(
					"No tags with '" + Consts.PAGE_ID + "' attribute in page"
				);
			}
			else
			{
				Element page = (Element) pages.get(0);
				
				return page.getAttributeValue(Consts.PAGE_ID);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		
		return pageId;
	}
	
	public static String getEntryUnitFieldName(String fieldId)
	{
		String fieldName = null;
		
		IFileSystem fileSystem = EFS.getLocalFileSystem();
		IFileStore entryUnitPageFileStore = fileSystem.getStore(URI.create(Consts.ENTRY_UNIT_PAGE_FILE_PATH));
		
		try
		{
			Builder parser = new Builder();
			Document entryUnitPage = parser.build(entryUnitPageFileStore.openInputStream(EFS.NONE, null));
			
			Nodes fields = entryUnitPage.query
			(
				Consts.ENTRY_UNIT_PAGE_ATTRIBUTES_QUERY + "/" + 
				Consts.ENTRY_UNIT_PAGE_CHILD_FIELD_NAME + "[@" + 
				Consts.PAGE_ID + "=\"" + fieldId + "\"]"
			);
			if(fields.size() > 1)
			{
				System.out.println
				(
					"More than one tag with '" + fieldId + 
					"' value for '" + Consts.PAGE_ID + "' attribute in default page"
				);
			}
			else if(fields.size() < 1)
			{
				System.out.println
				(
					"No tags with '" + fieldId + 
					"' value for '" + Consts.PAGE_ID + "' attribute in default page"
				);
			}
			else
			{
				Element field = (Element) fields.get(0);
				
				fieldName = field.getAttributeValue(Consts.TAG_ATTRIBUTE_NAME);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		
		return fieldName;
	}
	
	public static String getEntryUnitFieldType(String fieldId)
	{
		String fieldType = null;
		
		IFileSystem fileSystem = EFS.getLocalFileSystem();
		IFileStore entryUnitPageFileStore = fileSystem.getStore(URI.create(Consts.ENTRY_UNIT_PAGE_FILE_PATH));
		
		try
		{
			Builder parser = new Builder();
			Document entryUnitPage = parser.build(entryUnitPageFileStore.openInputStream(EFS.NONE, null));
			
			Nodes fields = entryUnitPage.query
			(
				Consts.ENTRY_UNIT_PAGE_ATTRIBUTES_QUERY + "/" + 
				Consts.ENTRY_UNIT_PAGE_CHILD_FIELD_NAME + "[@" + 
				Consts.PAGE_ID + "=\"" + fieldId + "\"]"
			);
			if(fields.size() > 1)
			{
				System.out.println
				(
					"More than one tag with '" + fieldId + 
					"' value for '" + Consts.PAGE_ID + "' attribute in default page"
				);
			}
			else if(fields.size() < 1)
			{
				System.out.println
				(
					"No tags with '" + fieldId + 
					"' value for '" + Consts.PAGE_ID + "' attribute in default page"
				);
			}
			else
			{
				Element field = (Element) fields.get(0);
				
				fieldType = field.getAttributeValue(Consts.MODEL_ATTRIBUTE_TYPE);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		
		return fieldType;
	}
	
	public static List<PossibleValue> getEntryUnitNamePossibleValues()
	{
		List<PossibleValue> values = new ArrayList<PossibleValue>();
		
		IFileSystem fileSystem = EFS.getLocalFileSystem();
		IFileStore entryUnitPageFileStore = fileSystem.getStore(URI.create(Consts.ENTRY_UNIT_PAGE_FILE_PATH));
		
		try
		{
			Builder parser = new Builder();
			Document entryUnitPage = parser.build(entryUnitPageFileStore.openInputStream(EFS.NONE, null));
			
			Nodes fields = entryUnitPage.query
			(
				Consts.ENTRY_UNIT_PAGE_ATTRIBUTES_QUERY + "/" + 
				Consts.ENTRY_UNIT_PAGE_CHILD_FIELD_NAME + "[@" + Consts.PAGE_ID + "]"
			);
			
			for(int i=0; i< fields.size(); i++)
			{
				Node fieldNode = fields.get(i);
				if(fieldNode instanceof Element)
				{
					Element field = (Element) fieldNode;
					values.add(new PossibleValue(field.getAttributeValue(Consts.PAGE_ID)));
				}
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return values;
	}
	
	public static String getUnitId(Document currentModel)
	{
		String unitId = null;
		
		if(currentModel != null)
		{
			unitId = currentModel.getRootElement().getAttributeValue(Consts.PAGE_ID);
		}
		return unitId;
	}
	
	public static int getUnitType(Document currentModel)
	{
		int unitType = 0;
		
		if(currentModel != null)
		{
			unitType = Integer.parseInt(currentModel.getRootElement().getAttributeValue(Consts.PAGE_UNIT_TYPE_NAME));
		}
		return unitType;
	}
	
	public static String getEntityName(Document currentModel)
	{
		String entityName = null;
		
		if(currentModel != null)
		{
			entityName = currentModel.getRootElement().getAttributeValue(Consts.PAGE_ENTITY_NAME);
		}
		return entityName;
	}
	
	public static List<String> getDisplayAttributes(Document currentModel)
	{
		List<String> displayAttributesList = new ArrayList<String>();
		
		if(currentModel != null)
		{
			Attribute displayAttributes = currentModel.getRootElement().getAttribute(Consts.PAGE_DISPLAY_ATTRIBUTES_NAME);
			
			String[] tokens = displayAttributes.getValue().split("\\s");
			
			for(int i=0; i<tokens.length; i++)
			{
				displayAttributesList.add(tokens[i]);
			}
		}
		return displayAttributesList;
	}
	
	public static List<String> getValues(Document currentModel, int unitType)
	{
		List<String> values = new ArrayList<String>();
		
		if(currentModel != null)
		{
			List<String> displayAttributesList = getDisplayAttributes(currentModel);
			
			if
			(
				unitType == Consts.DATA_UNIT || 
				unitType == Consts.MULTI_DATA_UNIT
			)
			{				
				Nodes attributeNodes = currentModel.query
				(
					Consts.MODEL_ATTRIBUTE_QUERY + "[@" + Consts.MODEL_ENTITY_ATTRIBUTE_NAME + "=\"" + Utility.getEntityName(currentModel) + 
					"\"]/" + Consts.MODEL_ATTRIBUTE_TAG
				);
				
				for(int i=0; i<attributeNodes.size(); i++)
				{
					Attribute attribute = ((Element)attributeNodes.get(i)).getAttribute(Consts.MODEL_ATTRIBUTE_NAME);
					
					if(displayAttributesList.contains(attribute.getValue()))
					{
						values.add(attribute.getValue());
					}
				}
			}
			else if(unitType == Consts.ENTRY_UNIT)
			{
				IFileSystem fileSystem = EFS.getLocalFileSystem();
				IFileStore entryUnitPageFileStore = fileSystem.getStore(URI.create(Consts.ENTRY_UNIT_PAGE_FILE_PATH));
				Builder parser = new Builder();
				try
				{
					Document entryUnitPage = parser.build(entryUnitPageFileStore.openInputStream(EFS.NONE, null));
					
					Nodes fieldNodes = entryUnitPage.query
					(
						Consts.ENTRY_UNIT_PAGE_ATTRIBUTES_QUERY + "/" + 
						Consts.ENTRY_UNIT_PAGE_CHILD_FIELD_NAME + "[@" + 
						Consts.PAGE_ID +  "]"
					);
					
					for(int i=0; i<fieldNodes.size(); i++)
					{
						Element field = (Element)fieldNodes.get(i);
						Attribute attribute = field.getAttribute(Consts.PAGE_ID);
						
						if(displayAttributesList.contains(attribute.getValue()))
						{
							values.add(attribute.getValue());
						}
					}
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
			}
		}
		return values;
	}
	
	public static Element getSingleChildByName(Element element, String childName)
	{
		if(element != null)
		{
			Nodes children = element.query(childName);
			
			if(children.size() > 1)
			{
				System.out.println("More than one tag named '" + childName + "' found in model");
			}
			else if(children.size() < 1)
			{
				System.out.println("No tags named '" + childName + "' found in model");
			}
			else
			{
				return (Element) children.get(0);
			}
		}
		return null;
	}
	
	public static Map<String,MyModelContent> getModelContent(Document currentModel)
	{
		Map<String,MyModelContent> modelContent = new HashMap<String,MyModelContent>();
		
		Nodes nodes = currentModel.query
		(
			Consts.MODEL_ATTRIBUTE_QUERY + "[@" + Consts.MODEL_ENTITY_ATTRIBUTE_NAME + "=\"" + Utility.getEntityName(currentModel) + 
			"\"]/" + Consts.MODEL_ATTRIBUTE_TAG + "[@" + Consts.MODEL_ATTRIBUTE_NAME + "]"
		);
//		Nodes nodes = currentModel.query("//attribute[@name]");
		
		for(int i=0; i<nodes.size(); i++)
		{
			Node node = nodes.get(i);
			if(node instanceof Element)
			{
				Element element = (Element) node;
				
//				Element label = getSingleChildByName(element, Consts.TAG_LABEL_NAME);
//				Element value = getSingleChildByName(element, Consts.TAG_VALUE_NAME);
				
				String nameAattributeValue = element.getAttributeValue(Consts.MODEL_ATTRIBUTE_NAME);
				
				if(nameAattributeValue != null)
				{
					MyModelContent content = new MyModelContent();
					content.setLabelContent(getAttributeContent(currentModel, nameAattributeValue, Consts.TAG_LABEL_NAME));
					content.setValueContent(getAttributeContent(currentModel, nameAattributeValue, Consts.TAG_VALUE_NAME));
					
					modelContent.put
					(
						nameAattributeValue, 
						content
					);
				}
			}
		}
		return modelContent;
	}
	
	public static String getAttributeContent(Document currentModel, String attributeValue, String tagName)
	{		
		String attributeContent = null;
		
		Element attribute = getAttributeElement(currentModel, attributeValue);
		if(attribute != null)
		{
//			attributeContent = attribute.getValue().trim();
			Nodes children = attribute.query(tagName);
			
			if(children.size() > 1)
			{
				System.out.println("More than one '" + tagName + "' tag in current model");
			}
			else if(children.size() < 1)
			{
				System.out.println("No '" + tagName + "' tag in current model");
			}
			else
			{
				// found in current model
				Element child = (Element) children.get(0);
				
				attributeContent = child.getValue().trim();
			}	
		}
		
		if(attributeContent != null)
		{
			if(attributeContent.startsWith(Consts.WR_START_TAG))
			{
				attributeContent = attributeContent.substring(attributeContent.indexOf(Consts.WR_START_TAG)+Consts.WR_START_TAG.length()).trim();
			}
			if(attributeContent.endsWith(Consts.WR_END_TAG))
			{
				attributeContent = attributeContent.substring(0, attributeContent.indexOf(Consts.WR_END_TAG)).trim();
			}
		}
		return attributeContent;
	}
	
	public static Element getAttributeElement(Document currentModel, String attributeValue)
	{		
		Element attribute = null;
		if(currentModel != null)
		{
//			Nodes attributes = currentModel.query("/attributes/attribute[@name=\"" + attributeValue + "\"]");
			
			Nodes attributes = currentModel.query
			(
				Consts.MODEL_ATTRIBUTE_QUERY + "[@" + Consts.MODEL_ENTITY_ATTRIBUTE_NAME + "=\"" + Utility.getEntityName(currentModel) + 
				"\"]/" + Consts.MODEL_ATTRIBUTE_TAG + "[@" + Consts.MODEL_ATTRIBUTE_NAME + "=\"" + attributeValue + "\"]"
			);
			
			if(attributes.size() > 1)
			{
				System.out.println("More than one tag with '" + attributeValue + "' value for '" + Consts.MODEL_ATTRIBUTE_NAME + "' attribute in current model");
			}
			else if(attributes.size() < 1)
			{
				System.out.println("No tag with '" + attributeValue + "' value for '" + Consts.MODEL_ATTRIBUTE_NAME + "' attribute in current model");
			}
			else
			{
				// found in current model
				attribute = (Element) attributes.get(0);
			}			
		}
		return attribute;
	}
	
	public static void synchOutput(IPath templatePath)
	{
		IFileSystem fileSystem = EFS.getLocalFileSystem();
		
		IFileStore templateFileStore = fileSystem.getStore(URI.create(templatePath.toString()));
		System.out.println("synchOutput.templateFileStore = " + templateFileStore.getName());
		
		IPath outputPath = templatePath.removeFileExtension().addFileExtension(Consts.OUTPUT_FILE_EXTENSION);
		System.out.println("synchOutput.outputPath = " + outputPath);
		
		IFileStore outputFileStore = fileSystem.getStore(URI.create(outputPath.toString()));
		System.out.println("synchOutput.outputFileStore = " + outputFileStore.getName());
		
		IPath modelPath = templatePath.removeFileExtension().addFileExtension(Consts.MODEL_FILE_EXTENSION);
		System.out.println("synchOutput.modelPath = " + modelPath);
		
		IFileStore modelFileStore = fileSystem.getStore(URI.create(modelPath.toString()));
		System.out.println("synchOutput.modelFileStore = " + modelFileStore.getName());
		
		if
		(
			(modelFileStore != null) &&
			(outputFileStore != null) &&
			(templateFileStore != null)
		)
		{
			try
			{					
				IFile modelFile = ResourcesPlugin.getWorkspace().getRoot().getFile(modelPath);
				modelFile.refreshLocal(IResource.DEPTH_INFINITE, null);
				
				IFile outputFile = ResourcesPlugin.getWorkspace().getRoot().getFile(outputPath);
				outputFile.refreshLocal(IResource.DEPTH_INFINITE, null);
				
				IFile templateFile = ResourcesPlugin.getWorkspace().getRoot().getFile(templatePath);
				templateFile.refreshLocal(IResource.DEPTH_INFINITE, null);
				
				try
				{
					Builder parser = new Builder();
					Document modelDocument = parser.build(modelFile.getContents());
					Document templateDocument = parser.build(templateFile.getContents());
					
//					Element templateRootElement = templateDocument.getRootElement();
//					XPathContext xpathContext = XPathContext.makeNamespaceContext(templateRootElement);
//					Nodes wrNodes = templateDocument.query("//wr:array", xpathContext);
//					
//					String currentOutput = "";
					
					Nodes bodies = templateDocument.query(Consts.TAG_BODY_QUERY);
					
					ByteArrayInputStream bIn = null;
					if(bodies.size() > 1)
					{
						System.out.println("More than one body tag in template");
					}
					else if(bodies.size() < 1)
					{
						System.out.println("No body tags in template");
					}
					else
					{				
						Element body = (Element) bodies.get(0);
						body.detach();
//						currentOutput = getOutput(body, null);
						
						ByteArrayOutputStream bOut = new ByteArrayOutputStream();
						MyOutputSerializer s = new MyOutputSerializer(bOut, modelDocument);
						
						s.write(new Document(body));
						
//						for(int i=0; i<body.getChildCount(); i++)
//						{
//							Node childNode = body.getChild(i);
//							if(childNode instanceof Element)
//							{
//								Element childElement = (Element) childNode;
//								childElement.detach();
//								s.write(new Document(childElement));
//							}
//						}
//						s.write(body.getDocument());
						
						byte[] bytes = bOut.toByteArray();
						
						bIn = new ByteArrayInputStream(bytes);
					}
					
//					for(int i=0; i<wrNodes.size(); i++)
//					{
//						Element element = (Element) wrNodes.get(i);
//						String varAttributeValue = element.getAttributeValue("name");
//						
//						ParentNode parent = element.getParent();
//						parent.removeChild(element);
//						
//						String content = "";
//						if(Consts.TAG_LABEL_NAME.equals(element.getLocalName()))
//						{
//							content = modelContent.get(varAttributeValue).getLabelContent();
//						}
//						else if(Consts.TAG_VALUE_NAME.equals(element.getLocalName()))
//						{
//							content = modelContent.get(varAttributeValue).getValueContent();
//						}
//						
//						System.out.println(content);
//						output += content;
//						//Element newElement = new Element(parser.build(.getRootElement());
//						//parent.appendChild(newElement);
//					}
					
					if(!outputFile.exists())
					{
//						outputFile.create(new ByteArrayInputStream(templateDocument.toXML().getBytes()), IResource.FORCE, null);
						
						outputFile.create(bIn != null ? bIn : new ByteArrayInputStream("".getBytes()), IResource.FORCE, null);
//						outputFile.create(new ByteArrayInputStream(output.getBytes()), IResource.FORCE, null);
					}
					else
					{
//						outputFile.setContents(new ByteArrayInputStream(templateDocument.toXML().getBytes()), EFS.NONE, null);
						
						outputFile.setContents(bIn != null ? bIn : new ByteArrayInputStream("".getBytes()), EFS.NONE, null);
//						outputFile.setContents(new ByteArrayInputStream(output.getBytes()), EFS.NONE, null);
					}
				}
				catch(Exception e)
				{
					e.printStackTrace();
					
					if(!outputFile.exists())
					{
						outputFile.create(new ByteArrayInputStream("".getBytes()), IResource.FORCE, null);
					}
					else
					{
						outputFile.setContents(new ByteArrayInputStream("".getBytes()), EFS.NONE, null);
					}
				}
			}
			catch(CoreException ce)
			{
				ce.printStackTrace();
			}
		}
	}
	
	public static String getOutput(Element element, String output)
	{
		String result = null;
		if(output == null)
		{
			result = "";
		}
		else
		{
			result = output;
		}
		
		if(Consts.TAG_LABEL_NAME.equals(element.getLocalName()))
		{
			result += "***LABEL***";
		}
		else if(Consts.TAG_VALUE_NAME.equals(element.getLocalName()))
		{
			result += "***VALUE***";
		}
		else
		{
			result += element.toXML();
		}
		
		Elements children = element.getChildElements();
		for(int i=0; i<children.size(); i++)
		{
			result = getOutput(children.get(i), result);
		}
		return result;
	}
	
	public static void manageElement(Document currentModel, Element attribute, String attributeContent, String tagName)
	{
		if(attribute != null)
		{
//			Element root = currentModel.getRootElement();
//			
//			root.removeChild(attribute);
//			
//			attribute.removeChildren();
//			
//			Text content = new Text(Consts.WR_START_TAG + attributeContent + Consts.WR_END_TAG);
//			attribute.appendChild(content);
//			
//			root.appendChild(attribute);
			
			Nodes nodes = currentModel.query
			(
				Consts.MODEL_ATTRIBUTE_QUERY + "[@" + Consts.MODEL_ENTITY_ATTRIBUTE_NAME + "=\"" + Utility.getEntityName(currentModel) + 
				"\"]/" + Consts.MODEL_ATTRIBUTE_TAG + "[@" + Consts.MODEL_ATTRIBUTE_NAME + "=\"" + 
				attribute.getAttributeValue(Consts.MODEL_ATTRIBUTE_NAME) + "\"]"
			);
			
			if(nodes.size() > 1)
			{
				System.out.println("More than one tag with '" + attribute.getAttributeValue(Consts.MODEL_ATTRIBUTE_NAME) + "' value for '" + Consts.PAGE_DISPLAY_ATTRIBUTES_NAME + "'attribute in default page");
			}
			else if(nodes.size() < 1)
			{
				System.out.println("No tags with '" + attribute.getAttributeValue(Consts.MODEL_ATTRIBUTE_NAME) + "' value for '" + Consts.PAGE_DISPLAY_ATTRIBUTES_NAME + "'attribute in default page");
			}
			else
			{				
				Element element = (Element) nodes.get(0);
				
				Nodes children = element.query(tagName);
				
				if(children.size() > 1)
				{
					System.out.println("More than one '" + tagName + "' tag in current model");
				}
				// create
				else if(children.size() < 1)
				{
					Element child = new Element(tagName);
					
					Text content = new Text(Consts.WR_START_TAG + attributeContent + Consts.WR_END_TAG);
					
					child.appendChild(content);
					
					element.appendChild(child);
				}
				// update
				else
				{					
					Element child = (Element) children.get(0);
					element.removeChild(child);
					child.removeChildren();
					
					Text content = new Text(Consts.WR_START_TAG + attributeContent + Consts.WR_END_TAG);
					
					child.appendChild(content);
					element.appendChild(child);
				}
				
//				Element element = (Element) nodes.get(0);
//				element.removeChildren();
//				
//				Text content = new Text(Consts.WR_START_TAG + attributeContent + Consts.WR_END_TAG);
//				
//				element.appendChild(content);
			}
		}
	}
	
	public static void findAllElements(org.w3c.dom.Element rootElement, List<org.w3c.dom.Element> elementList)
	{
		System.out.println("rootElement.getTagName() = " + rootElement.getLocalName());
		elementList.add(rootElement);
	    
	    NodeList children = rootElement.getChildNodes();
	    for(int i=0; i<children.getLength(); i++)
	    {
	    	org.w3c.dom.Node child = children.item(i);
	    	
	    	if(child instanceof org.w3c.dom.Element)
	    	{
	    		org.w3c.dom.Element element = (org.w3c.dom.Element) child;
	    		findAllElements(element, elementList);
	    	}
	    }
	}
	
	public static void findAllElementsByTagName(org.w3c.dom.Element rootElement, String tagName, List<org.w3c.dom.Element> elementList)
	{
		System.out.println("rootElement.getTagName() = " + rootElement.getLocalName());
		if(tagName.equals(rootElement.getLocalName()))
	    {
	    	elementList.add(rootElement);
		}
	    
	    NodeList children = rootElement.getChildNodes();
	    for(int i=0; i<children.getLength(); i++)
	    {
	    	org.w3c.dom.Node child = children.item(i);
	    	
	    	if(child instanceof org.w3c.dom.Element)
	    	{
	    		org.w3c.dom.Element element = (org.w3c.dom.Element) child;
	    		findAllElementsByTagName(element, tagName, elementList);
	    	}
	    }
	}
	
	public static void transformAllElementsByTagName(org.w3c.dom.Element rootElement, String tagName, ITagConverterContext context)
	{
		System.out.println("rootElement.getTagName() = " + rootElement.getLocalName());
		if(tagName.equals(rootElement.getLocalName()))
	    {
			MultiDataUnitTransformOperation transform = new MultiDataUnitTransformOperation();
			transform.setTagConverterContext(context);
			org.w3c.dom.Element newElement = transform.transform(rootElement, rootElement);
			org.w3c.dom.Node parent = rootElement.getParentNode();
			if(parent != null)
			{
				parent.removeChild(rootElement);
				parent.appendChild(newElement);
			}
		}
	    
	    NodeList children = rootElement.getChildNodes();
	    for(int i=0; i<children.getLength(); i++)
	    {
	    	org.w3c.dom.Node child = children.item(i);
	    	
	    	if(child instanceof org.w3c.dom.Element)
	    	{
	    		org.w3c.dom.Element element = (org.w3c.dom.Element) child;
	    		transformAllElementsByTagName(element, tagName, context);
	    	}
	    }
	}
	
	public static org.w3c.dom.Element getFirstParentElementByTagName(org.w3c.dom.Element startingElement, String tagName)
	{
		System.out.println("startingElement.getTagName() = " + startingElement.getLocalName());
		if(tagName.equals(startingElement.getLocalName()))
	    {
	    	return startingElement;
		}
		
		if(startingElement.getParentNode() != null)
		{
			if(startingElement.getParentNode() instanceof org.w3c.dom.Element)
			{
				return getFirstParentElementByTagName((org.w3c.dom.Element) startingElement.getParentNode(), tagName);
			}
		}
		return null;
	}
}